import { warn, log } from "cc";

/**
 * 事件监听方法
 */
export type ListenerFunc = (eventName: string, args?: any) => void;


class EventData {
    public event!: string;
    public listener!: ListenerFunc;
    public object: any;
}


/**
 * 事件管理
 */
class EventMananger {

    private static _instance: EventMananger = null;
    public static get instance(): EventMananger {
        if (this._instance == null) {
            this._instance = new EventMananger();
        }
        return this._instance;
    }


    private events: Map<string, EventData[]> = new Map();

    /**
     * 注册全局事件
     * @param event      事件名
     * @param listener   处理事件的侦听器函数
     * @param object     侦听函数绑定的作用域对象
     */
    on(event: string, listener: ListenerFunc, object: object) {
        if (!event || !listener) {
            warn(`注册【${event}】事件的侦听器函数为空`);
            return;
        }

        if (!this.events.has(event)) {
            this.events.set(event, []);
        }

        const listeners = this.events.get(event)
        for (let i = 0; i < listeners.length; i++) {
            let ed = listeners[i];
            if (ed.listener == listener && ed.object == object) {
                warn(`名为【${event}】的事件重复注册侦听器`);
            }
        }

        let data: EventData = new EventData();
        data.event = event;
        data.listener = listener;
        data.object = object;

        this.events.get(event).push(data);
    }

    /**
     * 监听一次事件，事件响应后，该监听自动移除
     * @param event     事件名
     * @param listener  事件触发回调方法
     * @param object    侦听函数绑定的作用域对象
     */
    once(event: string, listener: ListenerFunc, object: object) {
        let _listener: any = ($event: string, $args: any) => {
            this.off(event, _listener, object);
            _listener = null;
            listener.call(object, $event, $args);
        }
        this.on(event, _listener, object);
    }

    /**
     * 移除全局事件
     * @param event     事件名
     * @param listener  处理事件的侦听器函数
     * @param object    侦听函数绑定的作用域对象
     */
    off(event: string, listener: Function, object: object) {
        let list: Array<EventData> = this.events.get(event);

        if (list == undefined) {
            log(`名为【${event}】的事件不存在`);
            return;
        }

        let length = list.length;
        for (let i = 0; i < length; i++) {
            let bin: EventData = list[i];
            if (bin.listener == listener && bin.object == object) {
                list.splice(i, 1);
                break;
            }
        }

        if (list.length == 0) {
            this.events.delete(event);
        }
    }

    /** 
     * 触发全局事件 
     * @param event(string)      事件名
     * @param args(any)          事件参数
     */
    emit(event: string, args: any = null) {
        let list: Array<EventData> = this.events.get(event);

        if (list != undefined) {
            let temp: Array<EventData> = list.concat();
            for (let i = 0; i < temp.length; i++) {
                let eventBin = temp[i];
                eventBin.listener.call(eventBin.object, event, args);
            }
        }
    }

    /**
     * 清空所有事件监听
     */
    clear(): void {
        this.events.clear();
    }
}

export const eventManager = EventMananger.instance;